﻿using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using Esint.JudicialAuction.Model;
using Esint.JudicialAuction.Factory;
using Esint.JudicialAuction.IDAL;
using Esint.Common.Model;
using Esint.JudicialAuction.Model.Schedule;
using Esint.JudicialAuction.Model.Common;
using System.Linq;
using Esint.Common;
using System.Threading;
using Aspose.Cells;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Diagnostics;

namespace Esint.JudicialAuction.BLL
{
    /// <summary>
    /// 文件说明:  业务逻辑层
    /// 作    者: 谷明
    /// 生成日期: 2020年03月29日
    /// 模板版本: Esint.Template.BLL.BLL_01 版，适用于简单三层开发!
    /// 功能说明：
    /// </summary>
    public partial class Schedule_ShiftsService
    {
        Schedule_UserService userBll = new Schedule_UserService();
        /// <summary>
        /// 功    能: 保存对象
        /// 说    明: 当主键为空时，新增操作
        ///           当主键不为空，根据主键进行修改
        /// <summary>
        public void Save(Schedule_ShiftsInfo schedule_Shifts)
        {
            if (String.IsNullOrEmpty(schedule_Shifts.UserId) || !schedule_Shifts.WorkDate.HasValue || String.IsNullOrEmpty(schedule_Shifts.WorkTypeCode))
            {
                dataAccess.Insert(schedule_Shifts);
            }
            else
            {
                dataAccess.Update(schedule_Shifts);
            }
        }

        /// <summary>
        /// 验证是否满足自动排班的条件
        /// </summary>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public void ValidIfCanAutoSchedule(string startTime, string endTime, bool IsValidHistoryData)
        {
            DateTime startTimeObj = Convert.ToDateTime(startTime);
            DateTime endTimeObj = Convert.ToDateTime(endTime);

            if (startTimeObj > endTimeObj)
            {
                throw new AutoScheduleException("开始日期不能大于结束日期");
            }

            if(IsValidHistoryData)
            {
                var prevTime = startTimeObj.AddDays(-1).ToString("yyyy-MM-dd");

                //获得开始日期前一天的中心排班
                var lastDaySchedules = dataAccess.GetScheduleList(prevTime, prevTime, "1", null);
                if (lastDaySchedules == null)
                {
                    throw new AutoScheduleException("请设置或导入选择的开始时间前一天的中心和网信办的排班情况，以免因缺少历史数据导致排班逻辑错误");
                }
                else if (lastDaySchedules.Count == 0)
                {
                    throw new AutoScheduleException("请设置或导入选择的开始时间前一天的中心和网信办的排班情况，以免因缺少历史数据导致排班逻辑错误");
                }
            }

            //获得时间范围内网信办排班
            var scheduleList = dataAccess.GetScheduleList(startTime, endTime, "2", null);

            DateTime loopTime = Convert.ToDateTime(startTimeObj.ToString("yyyy-MM-dd"));

            List<string> emptyDateList = new List<string>();
            while (loopTime <= endTimeObj)
            {
                var qy = from t in scheduleList where t.WorkDate.Value == loopTime select t;
                if (qy.FirstOrDefault() == null)
                {
                    emptyDateList.Add(loopTime.ToString("yyyy-MM-dd"));
                }
                loopTime = loopTime.AddDays(1);
            }
            if (emptyDateList.Count > 0)
            {
                var errorInfo = $"请先设置以下日期的网信办排班情况{ string.Join(",", emptyDateList) }";
                throw new AutoScheduleException(errorInfo);
            }
        }

        /// <summary>
        /// 中心自动排班方法
        /// </summary>
        /// <param name="endTime"></param>
        /// <param name="OfficeSchedule"></param>
        public void AutoCreateCenterSchedule(string startTime, string endTime)
        {
            ValidIfCanAutoSchedule(startTime, endTime, true);

            DateTime startTimeObj = Convert.ToDateTime(startTime);
            DateTime endTimeObj = Convert.ToDateTime(endTime);

            var genderData = userBll.GetAvailableUserGenderNum();
            var officeData = dataAccess.GetScheduleList(startTime, endTime, "2", null);
            officeData = (from t in officeData where t.UserId != "xxx" select t).ToList();

            //删除旧排班记录
            DeleteScheduleByTimeSpan(startTime, endTime, "1");

            DateTime loopTime = Convert.ToDateTime(startTimeObj.ToString("yyyy-MM-dd"));
            while (loopTime <= endTimeObj)
            {
                var currentDateStr = loopTime.ToString("yyyy-MM-dd");
                OneDayWork oneDayWork = new OneDayWork(loopTime);

                //取出可白班排班人员
                var dayWorkUserList = userBll.GetCanBeAutoList(currentDateStr, 1);
                //随机8个人填入这次排班中
                //var personListForDay = GetPersonListByRules(dayWorkUserList, genderData, officeData, currentDateStr,"1"); //dayWorkUserList.GetRandomObject(8);
                var personListForDay = GetPersonListByRulesOld(dayWorkUserList);
                oneDayWork.CenterDaylightWork.PersonList.AddRange(personListForDay);
                SaveOnceWork(oneDayWork.CenterDaylightWork);

                //取出可夜班排班人员
                var nightWorkUserList = userBll.GetCanBeAutoList(currentDateStr, 2);
                //随机8个人填入这次排班中
                //var personListForNight = GetPersonListByRules(nightWorkUserList, genderData, officeData, currentDateStr,"2"); // nightWorkUserList.GetRandomObject(8);
                var personListForNight = GetPersonListByRulesOld(nightWorkUserList);
                oneDayWork.CenterNightWork.PersonList.AddRange(personListForNight);
                SaveOnceWork(oneDayWork.CenterNightWork);

                loopTime = loopTime.AddDays(1);
            }
        }

        /// <summary>
        /// 根据可用人员列表，取规则范围和平均原则的值班人员
        /// </summary>
        /// <param name="userList"></param>
        /// <returns></returns>
        List<Schedule_UserInfo> GetPersonListByRules(List<Schedule_UserInfo> userList, double[] genderData, List<Schedule_ShiftsInfo> officeData, string currentDate, string workType)
        {
            Debug.WriteLine($"取出可用人员{userList.Count}");

            #region 人数平均算法
            int expectMaleNum, hasMaleNum, expectFemaleNum, hasFemaleNum, totalNum, randomMaleNeed, randomFemaleNeed;
            var qyOfficeHas = from t in officeData where t.WorkDate.Value.ToString("yyyy-MM-dd") == currentDate && t.WorkTypeCode==workType select t;

            //算出需要的总数
            totalNum = qyOfficeHas.Count() + 8;

            //根据人员比例算出需要的数量
            expectMaleNum = (int)Math.Round((double)totalNum * genderData[0] / genderData[2]);
            expectFemaleNum = (int)Math.Round((double)totalNum * genderData[1] / genderData[2]);
            if (expectMaleNum + expectFemaleNum != totalNum)
            {
                throw new DataValidException("算法出错");
            }

            //根据网信办已有排班数据获得已经有的男员工和女员工数量
            hasMaleNum = (from t in officeData where t.WorkDate.Value.ToString("yyyy-MM-dd") == currentDate && t.UserGender == "1" && t.WorkTypeCode == workType select t).Count();
            hasFemaleNum = (from t in officeData where t.WorkDate.Value.ToString("yyyy-MM-dd") == currentDate && t.UserGender == "2" && t.WorkTypeCode == workType select t).Count();

            //得出需要随机出的男女人数
            randomMaleNeed = expectMaleNum - hasMaleNum;
            randomFemaleNeed = expectFemaleNum - hasFemaleNum;
            #endregion

            List<Schedule_UserInfo> FinallList = new List<Schedule_UserInfo>();
            //所有男的按排班次数正序排
            List<Schedule_UserInfo> MaleList = new List<Schedule_UserInfo>();
            var qyMale = from t in userList where t.Gender == "1" orderby t.ScheduleWeight ascending select t;
            if (qyMale.FirstOrDefault() != null)
            {
                MaleList.AddRange(qyMale.ToList());
            }

            //所有女的按排班次数正序排
            List<Schedule_UserInfo> FeMaleList = new List<Schedule_UserInfo>();
            var qyFeMale = from t in userList where t.Gender == "2" orderby t.ScheduleWeight ascending select t;
            if (qyFeMale.FirstOrDefault() != null)
            {
                FeMaleList.AddRange(qyFeMale.ToList());
            }
            else
            {
                //如果不包含女的直接取8个人return
                FinallList.AddRange(MaleList.Take(8));
                return FinallList;
            }

            var maleMinWeight = MaleList[0].ScheduleWeight;
            var maleMaxWeight = MaleList[MaleList.Count - 1].ScheduleWeight;
            var femaleMinWeight = FeMaleList[0].ScheduleWeight;
            var femaleMaxWeight = FeMaleList[FeMaleList.Count - 1].ScheduleWeight;

            int maleShortNum = 0, femaleShortNum = 0;

            #region 随机取男的算法
            if (MaleList.Count <= randomMaleNeed)
            {
                FinallList.AddRange(MaleList);
                if (MaleList.Count < randomMaleNeed)
                {
                    maleShortNum = randomMaleNeed - MaleList.Count;
                }
            }
            else
            {
                var minMatchedMale = (from t in MaleList where t.ScheduleWeight <= maleMinWeight select t);
                while (minMatchedMale.Count() < randomMaleNeed && maleMinWeight < maleMaxWeight)
                {
                    maleMinWeight++;
                    minMatchedMale = (from t in MaleList where t.ScheduleWeight <= maleMinWeight select t);
                }
                if (minMatchedMale.Count() == randomMaleNeed)
                {
                    FinallList.AddRange(minMatchedMale);
                }
                else if (minMatchedMale.Count() > randomMaleNeed)
                {
                    var restMaleList = minMatchedMale.ToList().GetRandomObject(randomMaleNeed);
                    FinallList.AddRange(restMaleList);
                }
                else
                {
                    maleShortNum = randomMaleNeed - minMatchedMale.Count();
                    FinallList.AddRange(minMatchedMale);
                }
            }
            #endregion

            #region 随机取女的算法
            if (FeMaleList.Count <= randomFemaleNeed)
            {
                FeMaleList.AddRange(FeMaleList);
                if (FeMaleList.Count < randomFemaleNeed)
                {
                    femaleShortNum = randomFemaleNeed - FeMaleList.Count;
                }
            }
            else
            {
                var minMatchedFeMale = (from t in FeMaleList where t.ScheduleWeight <= femaleMinWeight select t);
                while (minMatchedFeMale.Count() < randomFemaleNeed && femaleMinWeight < femaleMaxWeight)
                {
                    femaleMinWeight++;
                    minMatchedFeMale = (from t in FeMaleList where t.ScheduleWeight <= femaleMinWeight select t);
                }
                if (minMatchedFeMale.Count() == randomFemaleNeed)
                {
                    FinallList.AddRange(minMatchedFeMale);
                }
                else if (minMatchedFeMale.Count() > randomFemaleNeed)
                {
                    var restFeMaleList = minMatchedFeMale.ToList().GetRandomObject(randomFemaleNeed);
                    FinallList.AddRange(restFeMaleList);
                }
                else
                {
                    femaleShortNum = randomFemaleNeed - minMatchedFeMale.Count();
                    FinallList.AddRange(minMatchedFeMale);
                }
            }
            #endregion

            if (maleShortNum > 0 && femaleShortNum > 0)
            {
                throw new DataValidException($"人数不足，缺少人数：男少{maleShortNum}人，女少{femaleShortNum}人");
            }
            else if (maleShortNum == 0 && femaleShortNum > 0)
            {
                //用多出的男的补女的
                var restMales = from t in MaleList where !FinallList.Contains(t) select t;
                if (restMales.Count() >= femaleShortNum)
                {
                    FinallList.AddRange(restMales.ToList().GetRandomObject(femaleShortNum));
                }
                else
                {
                    throw new DataValidException($"人数不足，缺少人数：男多{restMales.Count()}人，女少{femaleShortNum}人");
                }
            }
            else if (maleShortNum > 0 && femaleShortNum == 0)
            {
                //用多出的女的补男的
                var restFeMales = from t in FeMaleList where !FinallList.Contains(t) select t;
                if (restFeMales.Count() >= maleShortNum)
                {
                    FinallList.AddRange(restFeMales.ToList().GetRandomObject(maleShortNum));
                }
                else
                {
                    throw new DataValidException($"人数不足，缺少人数：男少{maleShortNum}人，女少{restFeMales.Count()}人");
                }
            }
            
            if (FinallList.Count != 8)
            {
                throw new AutoScheduleException("算法取人数错误");
            }

            GC.Collect();

            List<string> UserIdList = new List<string>();

            for (int i = 0; i < FinallList.Count; i++)
            {
                if (!UserIdList.Contains(FinallList[i].UserId))
                {
                    UserIdList.Add(FinallList[i].UserId);
                }
            }

            if (UserIdList.Count != FinallList.Count)
            {
                string str = "我曹我曹从我草";
            }

            return FinallList;
        }

        /// <summary>
        /// 优化前算法
        /// </summary>
        /// <param name="userList"></param>
        /// <returns></returns>
        List<Schedule_UserInfo> GetPersonListByRulesOld(List<Schedule_UserInfo> userList)
        {
            Debug.WriteLine($"取出可用人员{userList.Count}");

            List<Schedule_UserInfo> FinallList = new List<Schedule_UserInfo>();
            //所有男的按排班次数正序排
            List<Schedule_UserInfo> MaleList = new List<Schedule_UserInfo>();
            var qyMale = from t in userList where t.Gender == "1" orderby t.ScheduleWeight ascending select t;
            if (qyMale.FirstOrDefault() != null)
            {
                MaleList.AddRange(qyMale.ToList());
            }

            //所有女的按排班次数正序排
            List<Schedule_UserInfo> FeMaleList = new List<Schedule_UserInfo>();
            var qyFeMale = from t in userList where t.Gender == "2" orderby t.ScheduleWeight ascending select t;
            if (qyFeMale.FirstOrDefault() != null)
            {
                FeMaleList.AddRange(qyFeMale.ToList());
            }
            else
            {
                //如果不包含女的直接取8个人return
                FinallList.AddRange(userList.Take(8));
                return FinallList;
            }

            //如果包含女的
            //找男的里面排班数最小的值
            int minPriority = MaleList[0].ScheduleWeight.Value;

            //查找排班数少的女生
            var matchedFeMaleList = FeMaleList.FindAll(x => x.ScheduleWeight <= minPriority);
            if (matchedFeMaleList != null && matchedFeMaleList.Count > 0)
            {
                //先加入四个男的
                FinallList.AddRange(MaleList.Take(4));

                matchedFeMaleList.Sort((x, y) => { if (x.ScheduleWeight < y.ScheduleWeight) { return -1; } else { return 1; } });
                if (matchedFeMaleList.Count > 4)
                {
                    var random4 = matchedFeMaleList.GetRandomObject(4);
                    FinallList.AddRange(random4);
                }
                else if (matchedFeMaleList.Count <= 4 && matchedFeMaleList.Count >= 2)
                {
                    //取2-4个的所有女生
                    FinallList.AddRange(matchedFeMaleList);
                    if (FinallList.Count < 8)
                    {
                        var femaleUp = 8 - FinallList.Count;

                        FinallList.AddRange(MaleList.Skip(4).Take(femaleUp));
                    }
                }
                else
                {
                    //再取4个男的
                    FinallList.AddRange(MaleList.Skip(4).Take(4));
                }
            }
            else
            {
                //没找到权限低的女生
                if (MaleList.Count < 8)
                {
                    //从所有用户取权重最小前8名
                    FinallList.AddRange(userList.Take(8));
                }
                else
                {
                    FinallList.AddRange(MaleList.Take(8));
                }
            }

            if (FinallList.Count != 8)
            {
                string debugInfo = "噢噢噢";
            }

            return FinallList;
        }

        /// <summary>
        /// 中心自动排班方法
        /// </summary>
        /// <param name="endTime"></param>
        /// <param name="OfficeSchedule"></param>
        public void AutoCreateOfficeSchedule(string startTime, string endTime)
        {
            DateTime startTimeObj = Convert.ToDateTime(startTime);
            DateTime endTimeObj = Convert.ToDateTime(endTime);

            DateTime loopTime = Convert.ToDateTime(startTimeObj.ToString("yyyy-MM-dd"));
            while (loopTime <= endTimeObj)
            {
                OneDayWork oneDayWork = new OneDayWork(loopTime);

                if (oneDayWork.OfficeDaylightWork != null)
                {
                    //随机0-4个人填入这次排班中
                    var OfficeNeedNum = CommonExtend.CustomRandom(0, 5);
                    if (OfficeNeedNum > 0)
                    {
                        //取出可白班排班人员
                        var dayWorkUserList = userBll.GetCanBeAutoList(loopTime.ToString("yyyy-MM-dd"), 1);
                        var personListForDay = dayWorkUserList.GetRandomObject(OfficeNeedNum);
                        oneDayWork.OfficeDaylightWork.PersonList.AddRange(personListForDay);
                    }
                    else
                    {
                        oneDayWork.OfficeDaylightWork.PersonList = null;
                    }
                    SaveOnceWork(oneDayWork.OfficeDaylightWork);
                }

                {
                    //随机0-4个人填入这次排班中
                    var OfficeNeedNum = CommonExtend.CustomRandom(0, 5);
                    if (OfficeNeedNum > 0)
                    {
                        //取出可夜班排班人员
                        var nightWorkUserList = userBll.GetCanBeAutoList(loopTime.ToString("yyyy-MM-dd"), 2);
                        //随机8个人填入这次排班中
                        var personListForNight = nightWorkUserList.GetRandomObject(OfficeNeedNum);
                        oneDayWork.OfficeNightWork.PersonList.AddRange(personListForNight);
                    }
                    else
                    {
                        oneDayWork.OfficeNightWork.PersonList = null;
                    }
                    SaveOnceWork(oneDayWork.OfficeNightWork);

                }

                System.GC.Collect();
                loopTime = loopTime.AddDays(1);
            }
        }

        /// <summary>
        /// 保存一次工作
        /// </summary>
        /// <param name="onceWork"></param>
        public void SaveOnceWork(OnceWork onceWork)
        {
            onceWork.ScheduleList = GetScheduleListFromOnceWork(onceWork);

            dataAccess.SaveScheduleAndUser(onceWork);
        }



        /// <summary>
        /// 从excel导入排班数据方法
        /// </summary>
        /// <param name="workbook"></param>
        public void ImportScheduleData(Workbook workbook)
        {
            Worksheet worksheet = workbook.Worksheets["排班数据"];
            List<Schedule_UserInfo> allUsers = userBll.GetAllUserList();

            List<OneDayWork> oneDayWorks = new List<OneDayWork>();

            var rowIndex = 2;
            while (!string.IsNullOrWhiteSpace(worksheet.Cells[rowIndex, 0].StringValue))
            {
                var workDate = worksheet.Cells[rowIndex, 0].StringValue;
                var centerDayPersons = worksheet.Cells[rowIndex, 1].StringValue;
                var centerNightPersons = worksheet.Cells[rowIndex, 2].StringValue;
                var officeDayPersons = worksheet.Cells[rowIndex, 3].StringValue;
                var officeNightPersons = worksheet.Cells[rowIndex, 4].StringValue;

                DateTime currTime;
                OneDayWork oneDayWork = null;
                if (DateTime.TryParse(workDate, out currTime))
                {
                    oneDayWork = new OneDayWork(currTime);
                }
                else
                {
                    throw new DataValidException($"第{(rowIndex + 1)}行的日期录入不正确。请更正后再导入");
                }

                //取中心白班
                if (centerDayPersons.IsNotNullOrEmpty())
                {
                    var personStrArr = centerDayPersons.Split(new char[] { '、' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < personStrArr.Length; i++)
                    {
                        var personName = personStrArr[i];
                        var personObject = allUsers.Find(x => x.UserName == personName);
                        if (personObject == null)
                        {
                            throw new DataValidException($"请先将人员【{personName}】录入到系统中（{workDate}的{GetColumnTypeFromExcel(1)}）");
                        }
                        Schedule_ShiftsInfo schedule = new Schedule_ShiftsInfo() { UserId = personObject.UserId, WorkDate = Convert.ToDateTime(workDate), WorkPlaceCode = "1", WorkTypeCode = "1" };
                        oneDayWork.CenterDaylightWork.ScheduleList.Add(schedule);
                        oneDayWork.CenterDaylightWork.PersonList.Add(personObject);
                    }
                }
                //取中心夜班
                if (centerNightPersons.IsNotNullOrEmpty())
                {
                    var personStrArr = centerNightPersons.Split(new char[] { '、' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < personStrArr.Length; i++)
                    {
                        var personName = personStrArr[i];
                        var personObject = allUsers.Find(x => x.UserName == personName);
                        if (personObject == null)
                        {
                            throw new DataValidException($"请先将人员【{personName}】录入到系统中（{workDate}的{GetColumnTypeFromExcel(2)}）");
                        }
                        Schedule_ShiftsInfo schedule = new Schedule_ShiftsInfo() { UserId = personObject.UserId, WorkDate = Convert.ToDateTime(workDate), WorkPlaceCode = "1", WorkTypeCode = "1" };
                        oneDayWork.CenterNightWork.ScheduleList.Add(schedule);
                        oneDayWork.CenterNightWork.PersonList.Add(personObject);
                    }
                }
                //取网信办白班
                if (officeDayPersons.IsNotNullOrEmpty() && oneDayWork.OfficeDaylightWork != null)
                {
                    var personStrArr = officeDayPersons.Split(new char[] { '、' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < personStrArr.Length; i++)
                    {
                        var personName = personStrArr[i];
                        var personObject = allUsers.Find(x => x.UserName == personName);
                        if (personObject == null)
                        {
                            throw new DataValidException($"请先将人员【{personName}】录入到系统中（{workDate}的{GetColumnTypeFromExcel(3)}）");
                        }
                        Schedule_ShiftsInfo schedule = new Schedule_ShiftsInfo() { UserId = personObject.UserId, WorkDate = Convert.ToDateTime(workDate), WorkPlaceCode = "1", WorkTypeCode = "1" };
                        oneDayWork.OfficeDaylightWork.ScheduleList.Add(schedule);
                        oneDayWork.OfficeDaylightWork.PersonList.Add(personObject);
                    }
                }
                //取网信办夜班
                if (officeNightPersons.IsNotNullOrEmpty())
                {
                    var personStrArr = officeNightPersons.Split(new char[] { '、' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < personStrArr.Length; i++)
                    {
                        var personName = personStrArr[i];
                        var personObject = allUsers.Find(x => x.UserName == personName);
                        if (personObject == null)
                        {
                            throw new DataValidException($"请先将人员【{personName}】录入到系统中（{workDate}的{GetColumnTypeFromExcel(4)}）");
                        }
                        Schedule_ShiftsInfo schedule = new Schedule_ShiftsInfo() { UserId = personObject.UserId, WorkDate = Convert.ToDateTime(workDate), WorkPlaceCode = "1", WorkTypeCode = "1" };
                        oneDayWork.OfficeNightWork.ScheduleList.Add(schedule);
                        oneDayWork.OfficeNightWork.PersonList.Add(personObject);
                    }
                }

                oneDayWorks.Add(oneDayWork);

                rowIndex++;
            }

            List<OnceWork> onceWorks = new List<OnceWork>();
            foreach (var oneDayWork in oneDayWorks)
            {
                if (oneDayWork.CenterDaylightWork.PersonList != null && oneDayWork.CenterDaylightWork.PersonList.Count > 0)
                {
                    oneDayWork.CenterDaylightWork.ScheduleList = GetScheduleListFromOnceWork(oneDayWork.CenterDaylightWork);
                    onceWorks.Add(oneDayWork.CenterDaylightWork);
                }
                if (oneDayWork.CenterNightWork.PersonList != null && oneDayWork.CenterNightWork.PersonList.Count > 0)
                {
                    oneDayWork.CenterNightWork.ScheduleList = GetScheduleListFromOnceWork(oneDayWork.CenterNightWork);
                    onceWorks.Add(oneDayWork.CenterNightWork);
                }
                if (oneDayWork.OfficeDaylightWork != null)
                {
                    oneDayWork.OfficeDaylightWork.ScheduleList = GetScheduleListFromOnceWork(oneDayWork.OfficeDaylightWork);
                    onceWorks.Add(oneDayWork.OfficeDaylightWork);
                }
                if (oneDayWork.OfficeNightWork.PersonList != null && oneDayWork.OfficeNightWork.PersonList.Count > 0)
                {
                    oneDayWork.OfficeNightWork.ScheduleList = GetScheduleListFromOnceWork(oneDayWork.OfficeNightWork);
                    onceWorks.Add(oneDayWork.OfficeNightWork);
                }
            }

            for (int i = 0; i < onceWorks.Count; i++)
            {
                var item = onceWorks[i];
                Debug.WriteLine(item.ToString());
                Debug.WriteLine(Environment.NewLine);
            }

            dataAccess.SaveOnceWorkList(onceWorks);

            string GetColumnTypeFromExcel(int colunmIndex)
            {
                string str = string.Empty;
                if (colunmIndex == 1)
                {
                    str = "中心白班";
                }
                else if (colunmIndex == 2)
                {
                    str = "中心夜班";
                }
                else if (colunmIndex == 3)
                {
                    str = "网信办白班";
                }
                else if (colunmIndex == 4)
                {
                    str = "网信办夜班";
                }
                return str;
            }
        }

        /// <summary>
        /// 获得分页查询日程
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public PagedList<OneDayWork> GetSchedulePagedList(string startTime, string endTime, string pageIndex, string pageSize)
        {
            var resList = new PagedList<OneDayWork>();

            DateTime startDate;
            if (!string.IsNullOrWhiteSpace(startTime))
            {
                startDate = Convert.ToDateTime(startTime);
            }
            DateTime endDate;
            if (!string.IsNullOrWhiteSpace(endTime))
            {
                endDate = Convert.ToDateTime(endTime);
            }

            var nPageIndex = int.Parse(pageIndex);
            var nPageSize = int.Parse(pageSize);

            var listMaxMinTime = dataAccess.GetMaxAndMinRecord(startTime, endTime);
            if (!(listMaxMinTime != null && listMaxMinTime.Count > 0))
            {
                resList.DataList = new List<OneDayWork>();
                resList.PageInfo = new PageSplit() { IsPageView = true, PageCount = 0, PageIndex = nPageIndex, PageSize = nPageSize, RecordCount = 0 };
            }
            else
            {
                if (resList.DataList == null)
                {
                    resList.DataList = new List<OneDayWork>();
                }

                startDate = listMaxMinTime[1];
                endDate = listMaxMinTime[0];

                var pagedStartDate = startDate.AddDays((nPageIndex - 1) * nPageSize);
                var pagedEndDate = startDate.AddDays(nPageIndex * nPageSize - 1);
                if (pagedEndDate > endDate)
                {
                    pagedEndDate = endDate;
                }

                var scheduleList = dataAccess.GetScheduleList(pagedStartDate.ToString("yyyy-MM-dd"), pagedEndDate.ToString("yyyy-MM-dd"), null, null);

                //创建返回对象列表
                var loopDate = pagedStartDate;
                while (loopDate <= pagedEndDate)
                {
                    OneDayWork oneDayWork = new OneDayWork(loopDate);

                    #region 初始化一天的两个单位的四个班
                    var qyPersonIdListOfCenterDaylight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "1" && t.WorkPlaceCode == "1" select t.UserId;
                    if (!string.IsNullOrWhiteSpace(qyPersonIdListOfCenterDaylight.FirstOrDefault()))
                    {
                        oneDayWork.CenterDaylightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfCenterDaylight.ToList());
                    }

                    var qyPersonIdListOfCenterNight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "2" && t.WorkPlaceCode == "1" select t.UserId;
                    if (!string.IsNullOrWhiteSpace(qyPersonIdListOfCenterNight.FirstOrDefault()))
                    {
                        oneDayWork.CenterNightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfCenterNight.ToList());
                    }

                    if (oneDayWork.OfficeDaylightWork != null)
                    {
                        var qyNotNeed = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.UserId == "xxx" && t.WorkTypeCode == "1" && t.WorkPlaceCode == "2" select t;
                        if (qyNotNeed.FirstOrDefault() == null)
                        {
                            var qyPersonIdListOfOfficeDaylight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "1" && t.WorkPlaceCode == "2" select t.UserId;
                            if (!string.IsNullOrWhiteSpace(qyPersonIdListOfOfficeDaylight.FirstOrDefault()))
                            {
                                oneDayWork.OfficeDaylightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfOfficeDaylight.ToList());
                            }
                        }
                        else
                        {
                            oneDayWork.OfficeDaylightWork.IsNeed = false;
                        }
                    }

                    {
                        var qyNotNeed = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.UserId == "xxx" && t.WorkTypeCode == "2" && t.WorkPlaceCode == "2" select t;
                        if (qyNotNeed.FirstOrDefault() == null)
                        {
                            var qyPersonIdListOfOfficeNight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "2" && t.WorkPlaceCode == "2" select t.UserId;
                            if (!string.IsNullOrWhiteSpace(qyPersonIdListOfOfficeNight.FirstOrDefault()))
                            {
                                oneDayWork.OfficeNightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfOfficeNight.ToList());
                            }
                        }
                        else
                        {
                            oneDayWork.OfficeNightWork.IsNeed = false;
                        }
                    }
                    #endregion

                    resList.DataList.Add(oneDayWork);

                    loopDate = loopDate.AddDays(1);
                }

                //组建分页对象
                var RecordCount = (int)Math.Ceiling((endDate - startDate).TotalDays) + 1;
                var pageCount = RecordCount / nPageSize;
                if (RecordCount % nPageSize != 0)
                {
                    pageCount++;
                }



                resList.PageInfo = new PageSplit() { IsPageView = true, PageCount = pageCount, PageIndex = nPageIndex, PageSize = nPageSize, RecordCount = (int)RecordCount };
            }

            return resList;
        }

        public List<Schedule_ShiftsInfo> GetScheduleListFromOnceWork(OnceWork onceWork)
        {
            List<Schedule_ShiftsInfo> ScheduleList = new List<Schedule_ShiftsInfo>();
            if (onceWork.PersonList != null && onceWork.PersonList.Count > 0)
            {
                //所有排班的人员排班数+1
                foreach (var user in onceWork.PersonList)
                {
                    user.Priority++;
                    user.ScheduleWeight++;
                    Schedule_ShiftsInfo oneSchedule = new Schedule_ShiftsInfo() { WorkDate = onceWork.WorkDate, UserId = user.UserId, WorkPlaceCode = ((int)onceWork.WorkPlace).ToString(), WorkTypeCode = ((int)onceWork.WorkType).ToString() };
                    ScheduleList.Add(oneSchedule);
                }
            }
            else
            {
                ScheduleList.Add(new Schedule_ShiftsInfo() { UserId = "xxx", WorkDate = onceWork.WorkDate, WorkPlaceCode = ((int)onceWork.WorkPlace).ToString(), WorkTypeCode = ((int)onceWork.WorkType).ToString() });
            }

            return ScheduleList;
        }

        /// <summary>
        /// 导出excel方法
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public string GetExportScheduleList(string startTime, string endTime, string saveDir, string templatePath)
        {
            var resList = new List<OneDayWork>();

            DateTime startDate;
            if (!string.IsNullOrWhiteSpace(startTime))
            {
                startDate = Convert.ToDateTime(startTime);
            }
            DateTime endDate;
            if (!string.IsNullOrWhiteSpace(endTime))
            {
                endDate = Convert.ToDateTime(endTime);
            }

            var listMaxMinTime = dataAccess.GetMaxAndMinRecord(startTime, endTime);
            if (!(listMaxMinTime != null && listMaxMinTime.Count > 0))
            {
                resList = new List<OneDayWork>();
            }
            else
            {
                if (resList == null)
                {
                    resList = new List<OneDayWork>();
                }

                startDate = listMaxMinTime[1];
                endDate = listMaxMinTime[0];

                var scheduleList = dataAccess.GetScheduleList(startDate.ToString("yyyy-MM-dd"), endDate.ToString("yyyy-MM-dd"), null, null);

                //创建返回对象列表
                var loopDate = startDate;
                while (loopDate <= endDate)
                {
                    OneDayWork oneDayWork = new OneDayWork(loopDate);

                    #region 初始化一天的两个单位的四个班
                    var qyPersonIdListOfCenterDaylight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "1" && t.WorkPlaceCode == "1" select t.UserId;
                    if (!string.IsNullOrWhiteSpace(qyPersonIdListOfCenterDaylight.FirstOrDefault()))
                    {
                        oneDayWork.CenterDaylightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfCenterDaylight.ToList());
                    }

                    var qyPersonIdListOfCenterNight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "2" && t.WorkPlaceCode == "1" select t.UserId;
                    if (!string.IsNullOrWhiteSpace(qyPersonIdListOfCenterNight.FirstOrDefault()))
                    {
                        oneDayWork.CenterNightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfCenterNight.ToList());
                    }

                    if (oneDayWork.OfficeDaylightWork != null)
                    {
                        var qyNotNeed = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.UserId == "xxx" && t.WorkTypeCode == "1" && t.WorkPlaceCode == "2" select t;
                        if (qyNotNeed.FirstOrDefault() == null)
                        {
                            var qyPersonIdListOfOfficeDaylight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "1" && t.WorkPlaceCode == "2" select t.UserId;
                            if (!string.IsNullOrWhiteSpace(qyPersonIdListOfOfficeDaylight.FirstOrDefault()))
                            {
                                oneDayWork.OfficeDaylightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfOfficeDaylight.ToList());
                            }
                        }
                        else
                        {
                            oneDayWork.OfficeDaylightWork.IsNeed = false;
                        }
                    }

                    {
                        var qyNotNeed = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.UserId == "xxx" && t.WorkTypeCode == "2" && t.WorkPlaceCode == "2" select t;
                        if (qyNotNeed.FirstOrDefault() == null)
                        {
                            var qyPersonIdListOfOfficeNight = from t in scheduleList where t.WorkDate.Value.ToString("yyyy-MM-dd") == loopDate.ToString("yyyy-MM-dd") && t.WorkTypeCode == "2" && t.WorkPlaceCode == "2" select t.UserId;
                            if (!string.IsNullOrWhiteSpace(qyPersonIdListOfOfficeNight.FirstOrDefault()))
                            {
                                oneDayWork.OfficeNightWork.PersonList = userBll.GetUserListByIdList(qyPersonIdListOfOfficeNight.ToList());
                            }
                        }
                        else
                        {
                            oneDayWork.OfficeNightWork.IsNeed = false;
                        }
                    }
                    #endregion

                    resList.Add(oneDayWork);

                    loopDate = loopDate.AddDays(1);
                }
            }

            return CreateExcel(resList, saveDir, templatePath, listMaxMinTime);
        }

        public string CreateExcel(List<OneDayWork> listOneDayWork, string saveDir, string templatePath, List<DateTime> dateTimes)
        {
            Workbook workbook = new Workbook(templatePath);
            Worksheet worksheet = workbook.Worksheets["Sheet1"];
            worksheet.Name = $"{dateTimes[1].ToString("yyyy-MM-dd")}至{dateTimes[0].ToString("yyyy-MM-dd")}排班计划";

            for (int i = 0; i < listOneDayWork.Count; i++)
            {
                var item = listOneDayWork[i];
                var rowIndex = i + 2;

                worksheet.Cells[rowIndex, 0].PutValue(item.WorkDateStr + " " + item.DayOfWeekStr);

                if (item.CenterDaylightWork.PersonList != null && item.CenterDaylightWork.PersonList.Count > 0)
                {
                    var qy = from t in item.CenterDaylightWork.PersonList select t.UserName;

                    string CenterDaylightStr = string.Join("、", qy.ToList());
                    worksheet.Cells[rowIndex, 1].PutValue(CenterDaylightStr);
                }

                if (item.CenterNightWork.PersonList != null && item.CenterNightWork.PersonList.Count > 0)
                {
                    var qy = from t in item.CenterNightWork.PersonList select t.UserName;

                    string CenterNightStr = string.Join("、", qy.ToList());
                    worksheet.Cells[rowIndex, 2].PutValue(CenterNightStr);
                }

                if (item.OfficeDaylightWork != null && item.OfficeDaylightWork.PersonList != null && item.OfficeDaylightWork.PersonList.Count > 0)
                {
                    var qy = from t in item.OfficeDaylightWork.PersonList select t.UserName;

                    string OfficeDaylightStr = string.Join("、", qy.ToList());
                    worksheet.Cells[rowIndex, 3].PutValue(OfficeDaylightStr);
                }

                if (item.OfficeNightWork != null && item.OfficeNightWork.PersonList != null && item.OfficeNightWork.PersonList.Count > 0)
                {
                    var qy = from t in item.OfficeNightWork.PersonList select t.UserName;

                    string OfficeNightStr = string.Join("、", qy.ToList());
                    worksheet.Cells[rowIndex, 4].PutValue(OfficeNightStr);
                }
            }

            if (!Directory.Exists(saveDir))
            {
                Directory.CreateDirectory(saveDir);
            }

            string saveFileName = $"{Guid.NewGuid().ToString()}.xlsx";
            string saveFullPath = saveDir + saveFileName;
            workbook.Save(saveFullPath);
            return saveFileName;
        }

        /// <summary>
        /// 根据查询条件查询排班记录
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="place"></param>
        /// <param name="workType"></param>
        /// <returns></returns>
        public List<Schedule_ShiftsInfo> GetScheduleList(string targetDate, string place, string workType)
        {
            return dataAccess.GetScheduleList(targetDate, targetDate, place, workType);
        }

        /// <summary>
        /// 获得用户个人的分页排班列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public ReturnTable GetScheduleListByUserId(string userId, string pageIndex, string pageSize, string startTime, string endTime)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                throw new DataValidException("用户id不能为空");
            }

            var nPageIndex = int.Parse(pageIndex);
            var nPageSize = int.Parse(pageSize);

            return dataAccess.GetScheduleListByUserId(userId, nPageIndex, nPageSize, startTime, endTime);
        }

        /// <summary>
        /// 检查换班合法性，并返回不合法的记录
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="targetWork"></param>
        public List<Schedule_ShiftsInfo> CheckSwitchTargetRight(string userId, OnceWork targetWork)
        {
            return dataAccess.CheckSwitchTargetRight(userId, targetWork);
        }

        /// <summary>
        /// 验证换班方法，没问题返回string.Empey
        /// </summary>
        /// <param name="switchOnceWork"></param>
        /// <returns></returns>
        public string ValidSwitch(SwitchOnceWork switchOnceWork)
        {
            if (switchOnceWork.Person1UserId == switchOnceWork.Person2UserId)
            {
                return "不能跟自己换班";
            }

            List<Schedule_ShiftsInfo> NotMatchList = new List<Schedule_ShiftsInfo>();
            var list1 = CheckSwitchTargetRight(switchOnceWork.Person1UserId, switchOnceWork.Person2OldWork);
            if (list1.IsNotNull() && list1.Count > 0)
            {
                NotMatchList.AddRange(list1);
            }
            var list2 = CheckSwitchTargetRight(switchOnceWork.Person2UserId, switchOnceWork.Person1OldWork);
            if (list2.IsNotNull() && list2.Count > 0)
            {
                NotMatchList.AddRange(list2);
            }

            if (NotMatchList.Count > 0)
            {
                List<string> ChangeDateList = new List<string>(){
                    switchOnceWork.Person1OldWork.WorkDateStr,
                    switchOnceWork.Person2OldWork.WorkDateStr,
                };

                StringBuilder errorInfo = new StringBuilder();
                for (int i = 0; i < NotMatchList.Count; i++)
                {
                    var item = NotMatchList[i];

                    if ((item.UserId == switchOnceWork.Person1UserId && item.WorkDate.Value.ToString("yyyy-MM-dd") == switchOnceWork.Person1OldWork.WorkDate.ToString("yyyy-MM-dd") 
                        && item.WorkTypeCode == ((int)switchOnceWork.Person1OldWork.WorkType).ToString() && item.WorkPlaceCode == ((int)switchOnceWork.Person1OldWork.WorkPlace).ToString())
                        || (item.UserId == switchOnceWork.Person2UserId && item.WorkDate.Value.ToString("yyyy-MM-dd") == switchOnceWork.Person2OldWork.WorkDate.ToString("yyyy-MM-dd")
                        && item.WorkTypeCode == ((int)switchOnceWork.Person2OldWork.WorkType).ToString() && item.WorkPlaceCode == ((int)switchOnceWork.Person2OldWork.WorkPlace).ToString())
                        )
                    {
                        continue;
                    }
                    
                    string oneError = $"<br />【{item.UserName}】在【{item.WorkDate.Value.ToString("yyyy-MM-dd")}】有【{item.WorkPlaceMeaning}】的【{item.WorkTypeMeaning}】";
                    errorInfo.AppendLine(oneError);
                }

                return errorInfo.ToString();
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 两人换班方法
        /// </summary>
        /// <param name="Person1Object"></param>
        /// <param name="Person2Object"></param>
        /// <returns></returns>
        public void SwithWorkForTwoPeople(JObject Person1Object, JObject Person2Object)
        {
            string userId1 = Person1Object["UserId"].Value<string>();
            int typeCode1 = Person1Object["WorkType"].Value<int>();
            int placeCode1 = Person1Object["Place"].Value<int>();
            DateTime workDate1 = Person1Object["WorkDate"].Value<DateTime>();
            OnceWork onceWork1 = new OnceWork((WorkType)typeCode1, (WorkPlace)placeCode1, workDate1);

            string userId2 = Person2Object["UserId"].Value<string>();
            int typeCode2 = Person2Object["WorkType"].Value<int>();
            int placeCode2 = Person2Object["Place"].Value<int>();
            DateTime workDate2 = Person2Object["WorkDate"].Value<DateTime>();
            OnceWork onceWork2 = new OnceWork((WorkType)typeCode2, (WorkPlace)placeCode2, workDate2);

            SwitchOnceWork switchOnceWork = new SwitchOnceWork() { Person1UserId = userId1, Person1OldWork = onceWork1, Person2UserId = userId2, Person2OldWork = onceWork2 };

            //验证换班合理性
            string errorInfo = ValidSwitch(switchOnceWork);
            if (string.IsNullOrEmpty(errorInfo))
            {
                //执行换班操作
                dataAccess.SaveSwitchWork(switchOnceWork);
            }
            else
            {
                throw new DataValidException($"【{Person1Object["UserName"].Value<string>()}】和【{Person2Object["UserName"].Value<string>()}】不能换班，原因如下：" + Environment.NewLine + errorInfo);
            }
        }

        /// <summary>
        /// 删除一个时间段内的排班记录
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        public void DeleteScheduleByTimeSpan(string startTime, string endTime, string place)
        {
            dataAccess.DeleteScheduleByTimeSpan(startTime, endTime, place);
        }
    }

}
